package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"sync"
)

var downloadPath string
var url string
var cookie string
var threads int
var songPattern *regexp.Regexp

func init() {
	var here = os.Args[0]
	here, err := filepath.Abs(here)
	if err != nil {
		fmt.Printf("Weird path: %s\n", err)
	}
	here = filepath.Dir(here)
	flag.StringVar(&downloadPath, "d", here, "下载目录")
	flag.StringVar(&url, "url", "", "网页URL")
	flag.StringVar(&cookie, "cookie", "", "Cookie")
	flag.IntVar(&threads, "t", 5, "同时下载数")

	songPattern = regexp.MustCompile("<a href=\"/song/([0-9]+)\" title=")
}

func fetchHtml(url string, cookie string) string {
	request, _ := http.NewRequest("GET", url, nil)
	request.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
	request.Header.Set("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4")
	request.Header.Set("Cache-Control", "max-age=0")
	request.Header.Set("Connection", "keep-alive")
	request.Header.Set("DNT", "1")
	request.Header.Set("Host", "music.baidu.com")
	request.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.66 Safari/537.36")
	if len(cookie) != 0 {
		request.Header.Set("Cookie", cookie)
	}
	client := &http.Client{}
	response, err := client.Do(request)
	if err == nil && response.StatusCode == 200 {
		defer response.Body.Close()
		body, _ := ioutil.ReadAll(response.Body)
		return string(body)
	}
	return ""
}

func findAllMatch(str string, p *regexp.Regexp) []string {
	all := p.FindAllStringSubmatch(str, -1)
	ret := make([]string, 0, len(all))
	for _, subs := range all {
		if len(subs) == 2 {
			ret = append(ret, subs[1])
		}
	}
	return ret
}

func parseSongIds(html string) []string {
	if len(html) > 0 {
		return findAllMatch(html, songPattern)

	}
	return nil
}

func getSongList(ids []string) []*Song {
	songs := make([]*Song, 0, len(ids))
	for _, id := range ids {
		song := newSong(id)
		songs = append(songs, song)
	}
	return songs
}

func download(songs []*Song) {
	if len(songs) > 0 {
		c := make(chan *Song, threads)
		var wg sync.WaitGroup
		for i := 0; i < threads; i++ {
			go func() {
				ok := true
				var song *Song
				for ok {
					if song, ok = <-c; ok {
						song.download()
						wg.Done()
					}
				}
			}()
		}

		for _, song := range songs {
			c <- song
			wg.Add(1)
		}
		close(c)
		wg.Wait()

	}
}

func main() {
	flag.Parse()
	html := fetchHtml(url, "")
	if len(html) > 0 {
		ids := parseSongIds(html)
		if len(ids) > 0 {
			songs := getSongList(ids)
			download(songs)
		} else {
			log.Fatal("无法取得歌曲列表.")
		}
	} else {
		log.Fatal("fetch URL: %s err", url)
	}
}
